namespace ContosoUniversity.Services.QueryServices
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using ContosoUniversity.DAL;
    using Models;
    using NRepository.Core.Query;
    using NRepository.EntityFramework;
    using System.Linq.Expressions;
    using NRepository.EntityFramework.Query;

    public class InstructorControllerQueryService : IInstructorControllerQueryService
    {
        private readonly IQueryRepository _QueryRepository;

        public InstructorControllerQueryService(IQueryRepository queryRepository)
        {
            _QueryRepository = queryRepository;
        }

        public async Task<IEnumerable<Instructor>> GetAllInstructorsOrderedByName()
        {
            var instructors = _QueryRepository.GetEntitiesAsync<Instructor>(
                 new OrderByQueryStrategy<Instructor>(i => i.LastName),
                 new EagerLoadingQueryStrategy<Instructor>(
                     i => i.OfficeAssignment,
                     i => i.Courses.Select(d => d.Department)));

            return await instructors;
        }

        public async Task<IEnumerable<Course>> GetAllCoursesAsync()
        {
            return await _QueryRepository.GetEntitiesAsync<Course>();
        }

        public async Task<IEnumerable<Instructor>> GetAllInstructorsWithAdditionalEntitesAsync(params string[] includes)
        {
            return await _QueryRepository.GetEntitiesAsync<Instructor>(new EagerLoadingQueryStrategy(includes));
        }

        public async Task<Course> GetCourseAync(int courseId)
        {
            return await _QueryRepository.GetEntityAsync<Course>(p => p.CourseID == courseId, false);
        }

        public async Task<Department> GetDepartmentAsync(int departmentId)
        {
            return await _QueryRepository.GetEntityAsync<Department>(p => p.InstructorID == departmentId, false);
        }

        public async Task<Instructor> GetInstructorWithAdditionalEntitiesAsync(int instructorId, params string[] includes)
        {
            return await _QueryRepository.GetEntityAsync<Instructor>(
                    new FindPersonByIdSpecificationStrategy<Instructor>(instructorId),
                    new EagerLoadingQueryStrategy(includes));
        }

        public async Task<Instructor> GetInstructorAsync(int instructorId, params Expression<Func<Instructor, object>>[] includes)
        {
            return await _QueryRepository.GetEntityAsync(
                new FindPersonByIdSpecificationStrategy<Instructor>(instructorId),
                new EagerLoadingQueryStrategy<Instructor>(includes));
        }

        public void LoadCourseEnrollmentsIntoCourse(Course course)
        {
            _QueryRepository.Load(
                course,
                p => p.Enrollments,
                new EagerLoadingQueryStrategy<Enrollment>(p => p.Student));
        }
    }
}
